/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

package test;

import java.awt.Font;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Random;

import javax.imageio.ImageIO;

import scenic.Gradient;
import scenic.LineCapStyle;
import scenic.LineJoinStyle;
import scenic.LinearColorFunction;
import scenic.Pattern;
import scenic.SceneContainer;
import scenic.SceneDoubleBuffer;
import scenic.ScenePrimitives;
import scenic.SceneTransform;
import scenic.ScenicCanvas;
import scenic.ScenicColor;
import scenic.ScenicGraphics;
import scenic.ScenicImage;
import scenic.SolidColor;
import scenic.Util;
import scenic.geom.TransformBuilder;
import scenic.show.SimpleMediaFile;

public class DemoWindow extends ScenicCanvas {
	private static final long serialVersionUID = 1L;
	private static int numWindows = 0;	
	private static final String imageFile = "images/Flower.jpg";	
	private SceneContainer rootScene;
	private SceneContainer magnifiedScene = new SceneContainer();
	private SceneContainer scene;
	private SceneContainer menuScene = new SceneContainer();
	private SceneContainer titleScene;
	private SceneDoubleBuffer contentScene;
	private SceneTransform contentSceneTransform = new SceneTransform(new AffineTransform());
	
	private int demoNum = 1;
	private ScenicImage image;
	private SimpleMediaFile player;	
	private double zoom = 1.0;
	private Point2D.Double offset = new Point2D.Double();
	private double leftMargin = 200;
	private double topMargin = 50;
	private double menuTop = topMargin + 5;
	private double menuRowHeight = 30;
	private int menuIndication = -1;
	private boolean showMagnification = false;
	
	String demoNames[] = {
		"Stroked paths",
		"Filled paths",
		"Text",
		"Paths",
		"Brushes",
		"Images",
		"Primitives",
		"Clipping",
		"Alpha blending",
		"Polygon antialiasing",
		"Combination",
		"Video"
	};
	
	public static void createWindow() {
		final Frame frame = new Frame();
		DemoWindow window = new DemoWindow();
		
		numWindows++;
		frame.setTitle("Java Scenic Demo");
		frame.add(window);
		frame.addWindowListener(
				new WindowAdapter() { 
					public void windowClosing(WindowEvent e) {
							frame.dispose();
							numWindows--;
							if(numWindows == 0)
								System.exit(1); 
						} 
				});
		frame.setBounds(new Rectangle(100, 100, 1100, 800));
		frame.setVisible(true);	
		window.requestFocus();
	}
	
	public static void main(String[] args) {
		createWindow();
	}
	
	private class DemoKeyListener implements KeyListener
	{
		public void keyPressed(KeyEvent e) {
			switch(e.getKeyCode()) {
			case KeyEvent.VK_UP:
				demoNum--;
				if(demoNum < 1)
					demoNum = demoNames.length;
				showDemo(demoNum);
				break;
			case KeyEvent.VK_DOWN:
				demoNum++;
				if(demoNum > demoNames.length)
					demoNum = 1;
				showDemo(demoNum);
				break;			
			case KeyEvent.VK_F2: {
					createWindow();
					break;
				}			
			case KeyEvent.VK_M: {
					if(showMagnification == false) {
						showMagnification = true;
						rootScene.add(magnifiedScene);
					} else {
						showMagnification = false;
						rootScene.remove(magnifiedScene);						
					}
				}
			}
		}

		public void keyReleased(KeyEvent e) {
		}

		public void keyTyped(KeyEvent e) {
		}
	}
	
	private class DemoMotionListener implements MouseListener, MouseMotionListener,
		MouseWheelListener {
		private Point dragStart;
		private Point2D.Double startOffset;
		private boolean dragging = false;

		public void mouseDragged(MouseEvent e) {
			setMagnificationPoint(e.getX(), e.getY());
			if(dragging) {
				offset.x = startOffset.x - (e.getX() - dragStart.x) / zoom;
				offset.y = startOffset.y - (e.getY() - dragStart.y) / zoom;		
				updateTransform();
			}
		}

		public void mouseMoved(MouseEvent e) {
			setMagnificationPoint(e.getX(), e.getY());
			if(e.getX() < leftMargin) {
				if(e.getY() > topMargin) {
					int n = (int)Math.floor((e.getY() - menuTop) / menuRowHeight);
					
					if(n < 0)
						n = 0;
					if(n >= demoNames.length)
						n = demoNames.length - 1;
					menuIndication = n;
					drawMenu();
				}
			}
		}

		public void mouseClicked(MouseEvent arg0) {
		}

		public void mouseEntered(MouseEvent arg0) {
		}

		public void mouseExited(MouseEvent arg0) {
		}

		public void mousePressed(MouseEvent e) {
			if(e.getX() < leftMargin) {
				if(e.getY() > getHeight() - menuRowHeight) {
					if(showMagnification == false) {
						showMagnification = true;
						rootScene.add(magnifiedScene);
					} else {
						showMagnification = false;
						rootScene.remove(magnifiedScene);						
					}				
				} else if(e.getY() > topMargin) {
					int n = (int)Math.floor((e.getY() - menuTop) / menuRowHeight);
					
					if(n < 0)
						n = 0;
					if(n >= demoNames.length)
						n = demoNames.length - 1;
					demoNum = n + 1;
					showDemo(demoNum);
				}
				dragging = false;
			} else {
				dragStart = e.getPoint();
				startOffset = (Point2D.Double)offset.clone();
				dragging = true;
			}
		}

		public void mouseReleased(MouseEvent arg0) {
		}

		public void mouseWheelMoved(MouseWheelEvent e) {
			double newZoom = zoom * Math.pow(0.9, e.getWheelRotation());
			
			offset.x -= (e.getX() - leftMargin) * (1.0 / newZoom - 1.0 / zoom);
			offset.y -= (e.getY() - topMargin) * (1.0 / newZoom - 1.0 / zoom);
			zoom = newZoom;
			updateTransform();
		}
	}
	
	public DemoWindow() {
		super();
			
//		setShowStatistics(true);
		addKeyListener(new DemoKeyListener());
		
		DemoMotionListener l = new DemoMotionListener();
		
		addMouseMotionListener(l);
		addMouseListener(l);
		addMouseWheelListener(l);
		showDemo(demoNum);
	}
	
	public void updateScene() {
		scene = new SceneContainer();
		ScenicGraphics g = new ScenicGraphics(scene);
		
		System.out.println("updateScene");
		
		contentScene = new SceneDoubleBuffer();
		contentSceneTransform.clear();
		contentSceneTransform.add(contentScene);
		
		g.push();
		g.translate(leftMargin, topMargin);
		g.add(contentSceneTransform);
//		g.add(contentScene);
		g.pop();
		titleScene = new SceneContainer();
		g.add(titleScene);
		g.translate(0, topMargin);
		g.add(menuScene);
		setBackground(new ScenicColor(1.0f, 1.0f, 1.0f));
			
		Font titleFont = new Font("SansSerif", Font.PLAIN, 32);
		g = new ScenicGraphics(titleScene);
				
		g.setFont(titleFont);
		g.setFillColor(new ScenicColor(0.8f, 0.8f, 1.0f));
		g.push();
//		g.translate(leftMargin, 0);
		
		Gradient gradient = new Gradient();
		LinearColorFunction f = new LinearColorFunction();
		
		f.addNode(0.0, new ScenicColor(0.8f, 0.8f, 0.8f, 0.9f).multiplyByAlpha());
//		f.addNode(50.0, new Color(0.9f, 0.9f, 0.9f, 0.9f).multiplyByAlpha());
//		f.addNode(95.0, new Color(0.8f, 0.8f, 0.8f, 0.9f).multiplyByAlpha());
		f.addNode(100.0, new ScenicColor(0.8f, 0.8f, 0.8f, 0.9f).multiplyByAlpha());
		
		gradient.setFunction(f);
		gradient.setType(Gradient.LINEAR);
		gradient.setTransform(Util.multiply(AffineTransform.getRotateInstance(90),
				AffineTransform.getScaleInstance(50, 50)));
		
		g.setFillBrush(gradient);
		g.rectangle(0, 0, 10000, 50);
		g.fill();
		g.translate(getWidth() / 2 - g.getTextLogicalBounds("Scenic Graphics Library Demo").getWidth() / 2, 35);
		g.setFillColor(new ScenicColor(0.0f, 0.0f, 0.0f));
		g.drawText("Scenic Graphics Library Demo");
		
		g.pop();
		drawMenu();
		paintDemo(demoNum);
		g = new ScenicGraphics(scene);
		g.setStrokeColor(new ScenicColor(0.0f));
		g.setLineWidth(3.0);
		g.moveTo(0, topMargin+0.5);
		g.lineTo(10000, topMargin+0.5);
		g.stroke();
		
		rootScene = new SceneContainer();
		rootScene.add(scene);
		if(showMagnification)
			rootScene.add(magnifiedScene);
		setScene(rootScene);
	}

	public void setMagnificationPoint(double x, double y) {
		ScenicGraphics g = new ScenicGraphics(magnifiedScene);
		double radius = 200.0;
		
		g.clear();
		g.translate(x, y);

		g.push();
		g.arc(0.0, 0.0, radius, radius, 0.0, 0.0, 360.0);
		g.close();
		g.clip();
		g.add(new SolidColor(new ScenicColor(1.0f)));
		g.scale(2.0, 2.0);
		g.translate(-x, -y);
		if(scene != null)
			g.add(scene);
		g.pop();
		
		g.arc(0.0, 0.0, radius, radius, 0.0, 0.0, 360.0);
		g.close();
		g.setLineWidth(3.0);
		g.stroke();
	}
	
	public void paintDemo(int num) {
		if(player != null) {
			player.free();
			player = null;
		}
		contentScene.clear();		
		switch(num) {
		case 1: strokedPathsDemo(); break;
		case 2: filledPathsDemo(); break;
		case 3: textDemo(); break;
		case 4: pathsDemo(); break;
		case 5: brushDemo(); break;
		case 6: imageDemo(); break;
		case 7: primitivesDemo(); break;
		case 8: clipDemo(); break;
		case 9: alphaBlendDemo(); break;
		case 10: antialiasDemo(); break;
		case 11: combinationDemo(); break;
		case 12: videoDemo(); break;
		}	
	}
	
	public void showDemo(int num) {
		demoNum = num;
		offset.x = offset.y = 0.0;
		zoom = 1.0;
		updateTransform();
		invalidateScene();
	}
	
	private void drawMenu() {
		ScenicGraphics g = new ScenicGraphics(menuScene);
		double h = getHeight() - topMargin;
		
		g.clear();
		g.setFont(new Font("SansSerif", Font.PLAIN, 18));
		g.setTextPosition(7, 4 -g.getTextLogicalBounds("W").getY());
		g.setFillColor(new ScenicColor(0.95f, 0.95f, 0.95f, 0.9f).multiplyByAlpha());
		g.rectangle(0, 0, leftMargin + 5, h);
		g.setStrokeColor(new ScenicColor(0.0f));
		g.setLineWidth(5.0);
		g.fill();
		g.moveTo(leftMargin + 4.5, 0);
		g.lineTo(leftMargin + 4.5, h);
		g.stroke();
		g.setFillColor(new ScenicColor(0.0f));
		
		for(int i = 0; i < demoNames.length; i++) {
			g.push();
			g.translate(0, i * menuRowHeight + 5);
			if(i == demoNum - 1) {
				g.push();
				Gradient gradient = new Gradient();
				LinearColorFunction f = new LinearColorFunction();
				
				f.addNode(0.0, new ScenicColor(0.75f, 0.70f, 0.6f, 0.9f).multiplyByAlpha());
//				f.addNode(20.0, new Color(0.6f, 0.6f, 1.0f, 0.9f).multiplyByAlpha());
//				f.addNode(80.0, new Color(0.6f, 0.6f, 1.0f, 0.9f).multiplyByAlpha());
				f.addNode(100.0, new ScenicColor(0.9f, 0.9f, 0.9f, 0.9f).multiplyByAlpha());
				
				gradient.setFunction(f);
				gradient.setType(Gradient.LINEAR);
				gradient.setTransform(Util.multiply(
						AffineTransform.getRotateInstance(00),
						AffineTransform.getScaleInstance(leftMargin, leftMargin)));
				
				g.setFillBrush(gradient);
				g.roundedRectangle(3, 0, leftMargin - 3, menuRowHeight, 5.0);
				g.fill();
				g.pop();
			}
			if(i == menuIndication) {
				g.push();
				g.setFillColor(new ScenicColor(0.3f, 0.3f, 0.3f, 0.2f));
				g.rectangle(3, 0, leftMargin - 3, menuRowHeight);
				g.fill();
				g.pop();
			}
			g.drawText(demoNames[i]);
			g.pop();
		}
		g.push();
		g.translate(2, 2 + h - menuRowHeight);
		g.arc(10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 360.0);
		g.setLineWidth(2.0);
		g.setStrokeColor(new ScenicColor(0.0f));
		g.moveTo(10.0 + 10.0 * Math.sin(Math.toRadians(45.0)), 10.0 + 10.0 * Math.sin(Math.toRadians(45.0)));
		g.lineTo(25.0, 25.0);
		g.stroke();
		g.translate(25, -5);
		g.drawText("Magnifying glass");
		g.pop();
/*		g.translate(10, 50);
		g.setFont(new Font("SansSerif", Font.PLAIN, 16));
		g.setFillColor(new Color(0, 0, 0));
		g.drawText("Use mouse to scroll and zoom the graphics."); */
	}
	
	public void updateTransform() {
		offset.x = Math.min(offset.x, 1240 - getWidth() / zoom);
		offset.y = Math.min(offset.y, 840 - (getHeight() - 50) / zoom);
		offset.x = Math.max(offset.x, 0);
		offset.y = Math.max(offset.y, 0);
		contentSceneTransform.setTransform(Util.multiply(
				AffineTransform.getScaleInstance(zoom, zoom),
				AffineTransform.getTranslateInstance(-offset.x, -offset.y)));
	}
	
	public double contentWidth() {
		return getWidth() - leftMargin;
	}
	
	public double contentHeight() {
		return getHeight() - topMargin;
	}
	
	public void strokedPathsDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor lineColor = new ScenicColor(0.0f, 0.0f, 0.0f);
			
		g.translate(20, 20);
		g.push();
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineWidth(20.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineWidth(4.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Bevel join");
		g.pop();
		
		g.push();
		g.translate(240, 0);
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineJoin(LineJoinStyle.MITER_JOIN);
		g.setStrokeColor(lineColor);
		g.setLineWidth(20.0);
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineWidth(4.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Miter join");
		g.pop();
		
		g.push();
		g.translate(240 * 2, 0);
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineJoin(LineJoinStyle.ROUND_JOIN);
		g.setStrokeColor(lineColor);
		g.setLineWidth(20.0);
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(100, 0);
		g.lineTo(200, 100);
		g.setLineWidth(4.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Round join");
		g.pop();
		
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.translate(0, 150);
		
		g.push();
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(20.0);
		g.setEndCap(LineCapStyle.BUTT_CAP);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(4.0);
		g.setEndCap(LineCapStyle.BUTT_CAP);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Butt cap");
		g.pop();

		g.push();
		g.translate(240 * 1, 0);
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(20.0);
		g.setEndCap(LineCapStyle.SQUARE_CAP);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(4.0);
		g.setEndCap(LineCapStyle.BUTT_CAP);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Square cap");
		g.pop();
		
		g.push();
		g.translate(240 * 2, 0);
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(20.0);
		g.setEndCap(LineCapStyle.ROUND_CAP);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.moveTo(0, 50);
		g.lineTo(200, 50);
		g.setLineWidth(4.0);
		g.setEndCap(LineCapStyle.BUTT_CAP);
		g.setStrokeColor(new ScenicColor(0.5f, 0.5f, 0.5f));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Round cap");
		g.pop();
		
		g.setEndCap(LineCapStyle.BUTT_CAP);
		g.translate(0, 150);
		
		g.push();
		g.translate(140 * 0, 0);
		g.moveTo(0, 0);
		g.lineTo(0, 100);
		g.lineTo(100, 100);
		g.lineTo(100, 0);
		g.setLineWidth(20.0);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Open");
		g.pop();
		
		g.push();
		g.translate(140 * 1, 0);
		g.moveTo(0, 0);
		g.lineTo(0, 100);
		g.lineTo(100, 100);
		g.lineTo(100, 0);
		g.close();
		g.setLineWidth(20.0);
		g.setStrokeColor(lineColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Closed");
		g.pop();
		
		float[] dashPattern1 = {5, 5};
		float[] dashPattern2 = {2, 2};
		float[] dashPattern3 = {1, 1};
		float[] dashPattern4 = {1, 2, 3, 2};
		
		g.translate(0, 150);
		g.push();
		g.translate(140 * 0, 0);
		g.setLineWidth(5.0);
		g.setStrokeColor(lineColor);
		g.setDashArray(dashPattern1);
		g.moveTo(0, 0);
		g.lineTo(200, 0);
		g.stroke();
		g.setDashArray(dashPattern2);
		g.moveTo(0, 30);
		g.lineTo(200, 30);
		g.stroke();
		g.setDashArray(dashPattern3);
		g.moveTo(0, 60);
		g.lineTo(200, 60);
		g.stroke();
		g.setDashArray(dashPattern4);
		g.moveTo(0, 90);
		g.lineTo(200, 90);
		g.stroke();
		g.setLineWidth(20.0);
		g.setDashArray(dashPattern3);
		g.setDashPhase(0.1);
		g.moveTo(220, 0);
		g.lineTo(220, 100);
		g.lineTo(320, 100);
		g.lineTo(320, 0);
		g.close();
		g.stroke();
		g.moveTo(350, 100);
		g.curveTo(new Point2D.Double(420, -50), new Point2D.Double(490, 100));
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Dash patterns");
		g.pop();
	}

	public void filledPathsDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor fillColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		
		g.translate(20, 20);
		g.push();
		g.moveTo(0, 0);
		g.lineTo(200, 0);
		g.lineTo(200, 200);
		g.lineTo(0, 200);
		g.setLineWidth(1.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setFillColor(fillColor);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.drawText("Simple path");
		g.pop();
		
		g.push();
		g.translate(240 * 1, 0);
		g.moveTo(0, 0);
		g.lineTo(200, 0);
		g.lineTo(200, 200);
		g.lineTo(0, 200);
		g.close();
		g.moveTo(50, 50);
		g.lineTo(50, 150);
		g.lineTo(150, 150);
		g.lineTo(150, 50);
		g.close();
		g.setLineWidth(1.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setFillColor(fillColor);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.drawText("Path with hole");
		g.pop();

		g.push();
		g.translate(240 * 2, 0);
		g.moveTo(0, 0);
		g.lineTo(200, 200);
		g.lineTo(0, 200);
		g.lineTo(200, 0);
		g.close();
		g.setLineWidth(1.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setFillColor(fillColor);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.drawText("Self-intersecting path");
		g.pop();
	}	

	public void textDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		
		g.translate(20, 20);
		for(int i = 8; i <= 40; i += 2) {
			g.translate(0, i + 4);
			g.setFont(new Font("SansSerif", Font.PLAIN, i));
			g.drawText("SansSerif font " + i + "px");	
		}
	}	

	public void pathsDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor strokeColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		
		g.translate(20, 20);

		g.push();
		g.translate(240 * 0, 0);
		g.moveTo(0, 100);
		g.lineTo(50, 0);
		g.lineTo(100, 100);
		g.lineTo(150, 0);
		g.lineTo(200, 100);
		g.setLineWidth(2.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(strokeColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Straigh lines");
		g.pop();

		g.push();
		g.translate(240 * 1, 0);
		g.moveTo(0, 100);
		g.curveTo(new Point2D.Double(100, -50), new Point2D.Double(200, 100));
		g.setLineWidth(2.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(strokeColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Quadratic Bezier curve");
		g.pop();
		
		g.push();
		g.translate(240 * 2, 0);
		g.moveTo(0, 100);
		g.curveTo(new Point2D.Double(30, -50), new Point2D.Double(150, 140), new Point2D.Double(200, 50));
		g.setLineWidth(2.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(strokeColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Cubic Bezier curve");
		g.pop();
		
		g.push();
		g.translate(240 * 0, 150);
		g.moveTo(0, 100);
		g.arcTo(100, 100, 0, -180, 0);
		g.setLineWidth(2.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(strokeColor);
		g.stroke();
		g.translate(0, 130);
		g.setFont(title2Font);
		g.drawText("Elliptic arc");
		g.pop();
		
		g.push();
		g.translate(240 * 0, 150 * 2);
		g.moveTo(0, 200);
		g.lineTo(50, 200);
		g.curveTo(new Point2D.Double(100, 0), new Point2D.Double(150, 200));
		g.lineTo(200, 200);
		g.curveTo(new Point2D.Double(400, 0), new Point2D.Double(100, 0), new Point2D.Double(300, 200));
		g.lineTo(350, 200);
		g.arcTo(100, 100, 0, -180, 0);
		g.lineTo(600, 200);
		g.setLineWidth(2.0);
		g.setLineJoin(LineJoinStyle.BEVEL_JOIN);
		g.setStrokeColor(strokeColor);
		g.stroke();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.drawText("Combination of different kinds of path segments");
		g.pop();
	}	
	
	public void brushDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor textColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		
		g.translate(20, 20);

		g.push();
		g.translate(240 * 0, 0);
		g.rectangle(0, 0, 200, 200);
		g.setFillColor(new ScenicColor(1.0f, 0.0f, 0.0f));
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Solid color");
		g.pop();
		
		Gradient gradient = new Gradient();
		LinearColorFunction f = new LinearColorFunction();
		
		f.addNode(-25.0, new ScenicColor(1.0f, 0.0f, 1.0f, 1.0f));
		f.addNode(0.0, new ScenicColor(0.0f, 0.0f, 1.0f, 1.0f));
		f.addNode(25.0, new ScenicColor(0.0f, 1.0f, 1.0f, 1.0f));
		f.addNode(50.0, new ScenicColor(0.0f, 1.0f, 0.0f, 1.0f));
		f.addNode(75.0, new ScenicColor(1.0f, 1.0f, 0.0f, 1.0f));
		f.addNode(100.0, new ScenicColor(1.0f, 0.0f, 0.0f, 1.0f));
		f.addNode(125.0, new ScenicColor(1.0f, 0.0f, 1.0f, 1.0f));
		
		gradient.setFunction(f);
		gradient.setType(Gradient.LINEAR);
		gradient.setTransform(AffineTransform.getScaleInstance(200.0, 200.0));
		
		g.push();
		g.translate(240 * 1, 0);
		g.rectangle(0, 0, 200, 200);
		g.setFillBrush(gradient);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Linear gradient");
		g.pop();

		gradient = new Gradient();
		gradient.setFunction(f);
		gradient.setType(Gradient.RADIAL);
		gradient.setTransform(new TransformBuilder().translateBy(100.0, 100.0).scaleBy(100.0, 100.0));
		
		g.push();
		g.translate(240 * 2, 0);
		g.rectangle(0, 0, 200, 200);
		g.setFillBrush(gradient);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Radial gradient");
		g.pop();
		
		gradient = new Gradient();
		gradient.setFunction(f);
		gradient.setType(Gradient.SQUARE);
		gradient.setTransform(new TransformBuilder().translateBy(100.0, 100.0).scaleBy(100.0, 100.0));
		
		g.push();
		g.translate(240 * 0, 240 * 1);
		g.rectangle(0, 0, 200, 200);
		g.setFillBrush(gradient);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Square gradient");
		g.pop();
		
		gradient = new Gradient();
		gradient.setFunction(f);
		gradient.setType(Gradient.CONICAL);
		gradient.setTransform(new TransformBuilder().translateBy(100.0, 100.0).scaleBy(100.0, 100.0));
		
		g.push();
		g.translate(240 * 1, 240 * 1);
		g.rectangle(0, 0, 200, 200);
		g.setFillBrush(gradient);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Conical gradient");
		g.pop();
		
		Pattern pattern = new Pattern(50, 50);
		{
			SceneContainer patternScene = new SceneContainer();
			ScenicGraphics g2 = new ScenicGraphics(patternScene);
		
			pattern.setPattern(patternScene);
			
			g2.moveTo(25, 5);
			g2.lineTo(45, 45);
			g2.lineTo(5, 45);
			g2.fill();
		}
		SceneTransform stm = new SceneTransform(AffineTransform.getRotateInstance(30));
		
		stm.add(pattern);
		g.push();
		g.setAntialias(true);
		g.translate(240 * 2, 240 * 1);
		g.rectangle(0, 0, 200, 200);
		g.setFillBrush(stm);
		g.fill();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Pattern");
		g.pop();
		
	}
	
	public void loadImage() {
		if(image == null) {
			ClassLoader loader = getClass().getClassLoader();
			URL resource = loader.getResource(imageFile);

			System.out.println("Image URL: " + resource);
			try {
				if(resource != null)
					image = new ScenicImage(ImageIO.read(resource));
				else
					image = new ScenicImage(ImageIO.read(new File(imageFile)));
			} catch (IOException e1) {
			}
		}		
	}
	
	public void imageDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);

		g.translate(20, 20);
		g.scale(0.45, 0.45);
		
		loadImage();
		if(image != null)
			g.drawImage(image);
	}
	
	private void drawStar(ScenicGraphics g, int n, double xc, double yc, double r1, double r2) {
		for(int i = 0; i < n * 2; i++) {
			double r = i % 2 == 0 ? r1 : r2;
			double a = Math.toRadians(360.0 / (n * 2) * i);
			double x = xc + Math.cos(a) * r;
			double y = yc + Math.sin(a) * r;
			
			if(i == 0)
				g.moveTo(x, y);
			else
				g.lineTo(x, y);
		}
		g.close();
	}
	
	public void clipDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font titleFont = new Font("SansSerif", Font.PLAIN, 32);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor textColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		
		g.translate(20, 20);

		g.setLineWidth(4.0);
		g.setStrokeColor(new ScenicColor(0.0f, 0.0f, 0.0f));

		g.push();
		g.translate(240 * 0, 0);
		g.rectangle(0, 0, 200, 200);
		g.setFillColor(new ScenicColor(1.0f, 1.0f, 0.5f));
		g.fill();
		for(int x = 0; x <= 10; x++) {
			g.moveTo(x * 20, 0);
			g.lineTo(x * 20, 200);
		}
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(180, 0);
		g.lineTo(180, 200);
		g.setFillColor(new ScenicColor(1.0f, 0.0f, 0.0f));
		g.fill();
		g.push();
		g.translate(50, 100);
		g.setFillColor(new ScenicColor(0.0f, 1.0f, 0.0f));
		g.setFont(titleFont);
		g.drawText("Some text");
		g.pop();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Without clipping");
		g.pop();
		
		g.push();
		g.translate(240 * 1, 0);
		g.push();
		drawStar(g, 12, 100, 100, 50, 100);
		g.clip();
		g.rectangle(0, 0, 200, 200);
		g.setFillColor(new ScenicColor(1.0f, 1.0f, 0.5f));
		g.fill();
		for(int x = 0; x <= 10; x++) {
			g.moveTo(x * 20, 0);
			g.lineTo(x * 20, 200);
		}
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(180, 0);
		g.lineTo(180, 200);
		g.setFillColor(new ScenicColor(1.0f, 0.0f, 0.0f));
		g.fill();
		g.push();
		g.translate(50, 100);
		g.setFillColor(new ScenicColor(0.0f, 1.0f, 0.0f));
		g.setFont(titleFont);
		g.drawText("Some text");
		g.pop();
		g.pop();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("With clipping");
		g.pop();

		g.push();
		g.setAntialias(true);
		g.translate(240 * 2, 0);
		g.push();
		drawStar(g, 12, 100, 100, 50, 100);
		g.clip();
		g.rectangle(0, 0, 200, 200);
		g.setFillColor(new ScenicColor(1.0f, 1.0f, 0.5f));
		g.fill();
		for(int x = 0; x <= 10; x++) {
			g.moveTo(x * 20, 0);
			g.lineTo(x * 20, 200);
		}
		g.stroke();
		g.moveTo(0, 100);
		g.lineTo(180, 0);
		g.lineTo(180, 200);
		g.setFillColor(new ScenicColor(1.0f, 0.0f, 0.0f));
		g.fill();
		g.push();
		g.translate(50, 100);
		g.setFillColor(new ScenicColor(0.0f, 1.0f, 0.0f));
		g.setFont(titleFont);
		g.drawText("Some text");
		g.pop();
		g.pop();
		g.translate(0, 230);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("With clipping and antialiasing");
		g.pop();
	}
	
	public void alphaBlendDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		double w = contentWidth() - 40;
		double h = contentHeight() - 40;
		

		g.translate(20, 20);

		g.rectangle(0, 0, w, h);
		g.clip();
		for(int x = 0; x < w; x += 20)
			for(int y = x % 40; y < h; y += 40)
				g.rectangle(x, y, 20, 20);
		g.setFillColor(new ScenicColor(0.48f, 0.48f, 0.48f));
		g.fill();
		for(int x = 0; x < w; x += 20)
			for(int y = (20 + x) % 40; y < h; y += 40)
				g.rectangle(x, y, 20, 20);
		g.setFillColor(new ScenicColor(0.52f, 0.52f, 0.52f));
		g.fill(); 
//		g.rectangle(0, 0, w, h);
//		g.setFillColor(new Color(0.8f));
//		g.fill();
		
		g.setAntialias(true);
		g.setLineJoin(LineJoinStyle.MITER_JOIN);
		Random random = new Random();
		
		for(int i = 0; i < 20; i++)
		{
			int type = (int)(random.nextDouble() * 3);
			float alpha = random.nextFloat() * 0.5f;
			ScenicColor color = new ScenicColor(
					random.nextFloat() * alpha, 
					random.nextFloat() * alpha, 
					random.nextFloat() * alpha, 
					alpha);
			
			if(type == 0 || type == 1)
			{
				g.moveTo(random.nextDouble() * w, random.nextDouble() * h);
				g.lineTo(random.nextDouble() * w, random.nextDouble() * h);
				g.lineTo(random.nextDouble() * w, random.nextDouble() * h);
				g.lineTo(random.nextDouble() * w, random.nextDouble() * h);
				g.lineTo(random.nextDouble() * w, random.nextDouble() * h);
			}
			
			if(type == 0)
			{
				g.setStrokeColor(color);
				g.setLineWidth(10 + random.nextDouble() * 50);
				g.stroke();
			}
			else if(type == 1)
			{
				g.setFillColor(color);
				g.fill();
			}
			else if(type == 2)
			{
				g.setFillColor(color);
				g.push();
				g.setFont(new Font("SansSerif", Font.PLAIN, (int)(25 + random.nextDouble() * 50)));
				g.translate(random.nextDouble() * w - 
						g.getTextLogicalBounds("Scenic Graphics Library").getWidth() / 2.0, 
						random.nextDouble() * h);
				g.drawText("Scenic Graphics Library");
				g.pop();
			}
		}
	}
	
	public void drawAliasingTestPattern(ScenicGraphics g, double maxr) {
		g.setFillColor(new ScenicColor(0.0f, 0.0f, 0.0f));
/*		for(double r = 10.0; r < maxr;)
		{
			g.arc(maxr, maxr, r, r, 0.0, 0.0, Math.toRadians(360.0));
			r += 100.0 / r;
			g.arc(maxr, maxr, r, r, 0.0, 0.0, -Math.toRadians(360.0));
			r += 100.0 / r;
		} */
		for(int i = 0; i < 40; i++)
		{
			g.moveTo(i / 40.0 * maxr * 2, 0);
			g.lineTo((0.5 + i) / 40.0 * maxr * 2, 0);
			g.lineTo(maxr, maxr * 2);
		}
		g.fill();
	}
	
	public void antialiasDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor textColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		
		g.translate(20, 20);
		g.setFillColor(new ScenicColor(0.0f, 0.0f, 0.0f));

		g.push();
		g.translate(440 * 0, 0);
		drawAliasingTestPattern(g, 200.0);
		g.translate(0, 430);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Without antialiasing");
		g.pop();
		
		g.push();
		g.setAntialias(true);
		g.translate(440 * 1, 0);
		drawAliasingTestPattern(g, 200.0);
		g.translate(0, 430);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("With antialiasing");
		g.pop();
	}
	
	public void primitivesDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
		Font title2Font = new Font("SansSerif", Font.PLAIN, 18);
		ScenicColor textColor = new ScenicColor(0.0f, 0.0f, 0.0f);
		ScenePrimitives primitives = new ScenePrimitives();
		int w = 100, h = 100;
		float positions[] = new float[2 * w * h];
		byte colors[] = new byte[4 * w * h];
		float texCoords[] = new float[2 * w * h];
		int indices[] = new int[(w - 1) * (h - 1) * 6];
		int i;
		
		for(int y = 0; y < h; y++)
		{
			for(int x = 0; x < w; x++)
			{
				double x2 = (x / (w - 1.0f)) - 0.5;
				double y2 = (y / (h - 1.0f)) - 0.5;
				double r = Math.hypot(x2, y2);
				i = x + y * w;
				
				colors[i * 4] = (byte)255;
				colors[i * 4 + 1] = (byte)255;
				colors[i * 4 + 2] = (byte)255;
				colors[i * 4 + 3] = (byte)255;
				
				positions[i * 2] = x * 5;
				positions[i * 2 + 1] = y * 5;
				
				texCoords[i * 2] = (float)(x / (w - 1.0f) + 0.05 * Math.sin(r * 35.0) * x2 / r);
				texCoords[i * 2 + 1] = (float)(y / (h - 1.0f) + 0.05 * Math.sin(r * 35.0) * y2 / r);
			}
		}
		i = 0;
		for(int y = 0; y < h - 1; y++)
		{
			for(int x = 0; x < w - 1; x++)
			{
				indices[i++] = x + y * w;
				indices[i++] = (x + 1) + y * w;
				indices[i++] = x + (y + 1) * w;
				
				indices[i++] = (x + 1) + (y + 1) * w;
				indices[i++] = (x + 1) + y * w;
				indices[i++] = x + (y + 1) * w;
			}
		}
		loadImage();
		
		primitives.setAttribute(ScenePrimitives.POSITION_ATTRIBUTE, 2, positions);
		primitives.setAttribute(ScenePrimitives.COLOR_ATTRIBUTE, 4, colors);
		primitives.setAttribute(ScenePrimitives.TEX_COORD1_ATTRIBUTE, 2, texCoords);
		primitives.setIndices(indices);
		primitives.setTexture(0, image);
		
		g.translate(20, 20);
		g.add(primitives);
		g.translate(0, 520);
		g.setFont(title2Font);
		g.setFillColor(textColor);
		g.drawText("Textured triangles");
	}	
	
	public void combinationDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);

		Gradient gradient = new Gradient();
		Gradient gradient2 = new Gradient();
		Gradient gradient3 = new Gradient();
		LinearColorFunction f = new LinearColorFunction();
		LinearColorFunction f2 = new LinearColorFunction();
		LinearColorFunction f3 = new LinearColorFunction();
		
		f.addNode(0.0, new ScenicColor(1.0f, 0.0f, 0.0f, 1.0f));
		f.addNode(1.0, new ScenicColor(1.0f, 1.0f, 0.0f, 1.0f));
		
		gradient.setFunction(f);
		gradient.setType(Gradient.LINEAR);
		gradient.setTransform(new TransformBuilder().rotateBy(-90).scaleBy(600.0, 1.0));

		f2.addNode(0.0, new ScenicColor(1.0f, 0.5f, 0.5f, 1.0f));
		f2.addNode(1.0, new ScenicColor(1.0f, 1.0f, 0.5f, 1.0f));
		
		gradient2.setFunction(f2);
		gradient2.setType(Gradient.LINEAR);
		gradient2.setTransform(new TransformBuilder().rotateBy(-90).scaleBy(600.0, 1.0));

		f3.addNode(0.0, new ScenicColor(0.0f, 0.0f, 0.5f, 1.0f));
		f3.addNode(1.0, new ScenicColor(0.5f, 0.0f, 0.5f, 1.0f));
		
		gradient3.setFunction(f3);
		gradient3.setType(Gradient.LINEAR);
		gradient3.setTransform(new TransformBuilder().rotateBy(-90).scaleBy(600.0, 1.0));
		
//		double a = 360.0 / 10.0 / 2.0;
		
		g.translate(20, 20);

		g.rectangle(0, 0, 700, 700);
		g.setStrokeColor(new ScenicColor(0.0f));
		g.setLineJoin(LineJoinStyle.MITER_JOIN);
		g.setLineWidth(10.0);
		g.setFillBrush(gradient3);
		g.fillAndStroke();
		g.setLineWidth(3.0);
/*		g.moveTo(295, 380);
		for(int i = 0; i < 10; i++) {
			g.arcTo(40, 80, 360.0 / 10.0 * i, -a, 180 + a);
		}
		g.close(); */
		for(double a = 0.0; a < 360.0; a+=0.5) {
			double ra = Math.toRadians(a);
			double x = 350 + Math.cos(ra) * 150 + Math.cos(ra * 8.0) * 150 + Math.cos(ra * 70.0) * 0;
			double y = 350 + Math.sin(ra) * 150 + Math.sin(ra * 8.0) * 150 + Math.sin(ra * 70.0) * 0;
			
			if(a == 0.0)
				g.moveTo(x, y);
			else
				g.lineTo(x, y);
		}
		g.setAntialias(true);
		g.close();
		g.setFillBrush(gradient);
		g.setStrokeBrush(gradient2);
		g.fillAndStroke();
	}	
	
	public File getResourceFile(String name) throws IOException {
		ClassLoader loader = getClass().getClassLoader();
		URL resource = loader.getResource(name);
		
		if(resource != null) {
			File temp = File.createTempFile("temp_resource", name.substring(name.lastIndexOf(".") - 1));
			FileOutputStream output = new FileOutputStream(temp);
			InputStream input = resource.openStream();
			
			try {
				int l;
				byte data[] = new byte[1000];
				
				while((l = input.read(data)) != -1)
					output.write(data, 0, l);
			} catch(IOException e) {
			}
			output.close();
			input.close();
			temp.deleteOnExit();
			
			return temp;
		} else {
			return new File(name);
		}
	}
	
	public void videoDemo() {
		ScenicGraphics g = new ScenicGraphics(contentScene);
//		String filename = "C:\\Documents and Settings\\Jouni Tulkki\\Omat tiedostot\\Omat videotiedostot\\Corall Reef\\Frigate birds in mangal.avi";
//		String file = "C:\\DXSDK\\Samples\\Media\\skiing.avi";		
//		String filename = "C:\\Video\\Antonwithagen-AndaluciaInward197.mov";
		String filename = "images/ir_launch.mpg";
		File file;
		
		try {
			file = getResourceFile(filename);
		} catch(IOException e) {
			return;
		}

		System.out.println("File name: " + file.getPath());
		player = new SimpleMediaFile(file.getPath());
		
		player.play();
		g.translate(10, 10);
		g.scale(2, 2);
		g.drawImage(player.getImage());
		g.translate(300, 10);
		g.scale(0.3, 0.3);
		g.drawImage(player.getImage());
		g.translate(0, 250);
		g.drawImage(player.getImage());
		g.translate(0, 250);
		g.drawImage(player.getImage());
	}
}
